import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import org.hyperledger.fabric.gateway.*;
import org.hyperledger.fabric.gateway.impl.GatewayImpl;
import org.hyperledger.fabric.sdk.Peer;

import java.io.IOException;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeoutException;


public final class App {
    // 网络配置文件的路径
    private static final Path NETWORK_CONFIG_PATH = Paths.get("src", "main", "resources", "connection.json");

    // 证书和私钥的路径
    private static final Path cryptoPath = Paths.get("src", "main", "resources", "crypto-config", "organizations",
            "peerOrganizations", "org1.example.com");
    private static final Path certPath = cryptoPath.resolve(Paths.get("users", "User1@org1.example.com", "msp", "signcerts", "User1@org1.example.com-cert.pem"));
    private static final Path keyDirPath = cryptoPath.resolve(Paths.get("users", "User1@org1.example.com", "msp", "keystore", "priv_sk"));
    private static final Path tlsCertPath = cryptoPath.resolve(Paths.get("peers", "peer0.org1.example.com", "tls", "ca.crt"));

    private Gateway gateway;
    private Network network;

    private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();

    public static void main(final String[] args) throws Exception {
        X509Certificate certificate = null;
        PrivateKey privateKey = null;
        Gateway gateway = null;
        try {
            //使用org1中的user1初始化一个网关wallet账户用于连接网络
            Wallet wallet = Wallets.newInMemoryWallet();

            // 读取证书
            certificate = readX509Certificate(certPath);

            // 读取私钥
            privateKey = getPrivateKey(keyDirPath);

            wallet.put("user", Identities.newX509Identity("Org1MSP", certificate, privateKey));

            //根据connection.json 获取Fabric网络连接对象
            GatewayImpl.Builder builder = (GatewayImpl.Builder) Gateway.createBuilder()
                    .identity(wallet, "user")
                    .networkConfig(NETWORK_CONFIG_PATH);
            //连接网关
            gateway = builder.connect();
            //获取mychannel通道
            Network network = gateway.getNetwork("mychannel");
            //获取合约对象
            Contract contract = network.getContract("basic");

            //调用链码的接口
            initLedger(contract);
            getAllAssets(contract);
            //readAssetById(contract,"asset1");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //初始化账本
    private static void initLedger(Contract contract) {
        try {
            contract.submitTransaction("InitLedger");
            System.out.println("initLedger successfully");
        } catch (ContractException e) {
            e.printStackTrace();
        } catch (TimeoutException e){
            e.printStackTrace();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    //查询现有资产
    private static void getAllAssets(Contract contract) {
        try {
            byte[] queryAllAssets = contract.evaluateTransaction("GetAllAssets");
            System.out.println("所有资产：" + prettyJson(queryAllAssets));
        } catch (ContractException e) {
            e.printStackTrace();
        }
    }

    //创建资产
    private static void createAsset(Contract contract, String assetId) {
        try {
            contract.submitTransaction("CreateAsset", assetId, "yellow", "5", "Tom", "1300");
        } catch (ContractException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //根据ID获取资产的信息
    private static void readAssetById(Contract contract,String assetId) {
        try {
            byte[] evaluateResult = contract.evaluateTransaction("ReadAsset", assetId);
            System.out.println("ID:"+ assetId +"\n资产的信息：" + prettyJson(evaluateResult));
        }catch (ContractException e){
            e.printStackTrace();
        }
    }

    // 读取证书
    private static X509Certificate readX509Certificate(final Path certificatePath) {
        X509Certificate x509Certificate=null;
        try (Reader certificateReader = Files.newBufferedReader(certificatePath, StandardCharsets.UTF_8)) {
            x509Certificate =  Identities.readX509Certificate(certificateReader);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } finally {
            return x509Certificate;
        }
    }

    // 读取私钥
    private static PrivateKey getPrivateKey(final Path privateKeyPath)  {
        PrivateKey privateKey = null;
        try (Reader privateKeyReader = Files.newBufferedReader(privateKeyPath, StandardCharsets.UTF_8)) {
            privateKey =  Identities.readPrivateKey(privateKeyReader);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } finally {
            return privateKey;
        }
    }

    private static String prettyJson(final byte[] json) {
        return prettyJson(new String(json, StandardCharsets.UTF_8));
    }

    private static String prettyJson(final String json) {
        JsonElement parsedJson = new JsonParser().parse(json);
        return gson.toJson(parsedJson);
    }

}
